package com.oig.sys.base.app.impl;

import com.oig.common.constants.CommonEnum;
import com.oig.common.exception.BadRequestException;
import com.oig.sys.base.app.IAppCurrRateService;
import com.oig.sys.base.app.spider.CurrRateBocPageProcessor;
import com.oig.sys.base.app.spider.CurrRateBocPipeline;
import com.oig.sys.base.app.util.DateTimeUtils;
import com.oig.sys.base.dto.CurrRateDto;
import com.oig.sys.base.service.ITbCurrRateHisService;
import com.oig.sys.base.service.ITbCurrRateService;
import com.oig.sys.base.service.ITbCurrencyService;
import com.oig.sys.base.vo.CurrRateHisVo;
import com.oig.sys.base.vo.CurrRateVo;
import com.oig.sys.base.vo.CurrencyVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import us.codecraft.webmagic.Spider;

import java.time.YearMonth;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Component
@RequiredArgsConstructor
public class AppCurrRateServiceImpl implements IAppCurrRateService {

    private final ITbCurrRateService currRateService;
    private final ITbCurrencyService currencyService;
    private final ITbCurrRateHisService currRateHisService;

    @Override
    public CurrRateVo addTbCurrRate(CurrRateDto currRateDto) {
        CurrRateVo currRateVo = this.currRateService.addTbCurrRate(currRateDto);
        if (currRateVo.getRmbRate()==null){
            return currRateVo;
        }
        return currRateVo;
    }


    @Override
    public CurrRateVo updateTbCurrRate(CurrRateDto currRateDto) {
        CurrRateVo currRateVo = this.currRateService.updateTbCurrRate(currRateDto);
        if (currRateVo.getRmbRate()==null){
            return currRateVo;
        }
        return currRateVo;
    }

    @Override
    public void delTbCurrRate(Integer id) {
        this.currRateService.delTbCurrRate(id);
    }

    @Override
    public CurrRateVo getCurrRateByCurr(String currency, String type) {
        return this.currRateService.getCurrRateByCurr(currency, type);
    }

    @Override
    public List<CurrRateVo> listByCustomsCurrAndYearMonth(List<String> currency, YearMonth yearMonth) {
        boolean thisMonth = YearMonth.now().equals(yearMonth);

        yearMonth = yearMonth.plusMonths(-1); //查询某个月的海关汇率时, 汇率发布日期是上个月的第三个星期三
        if (thisMonth) {
            //如果查询当月海关汇率不走历史表, 增加查询速度
            return currRateService.findAllByCurrAndYearMonth(currency, yearMonth,
                    CommonEnum.FlagEnum.TRUE_FLAG.getCode());
        } else {
            return this.currRateHisService.queryCurrRateByCodeAndYearMonth(currency, yearMonth);
        }

    }


    @Override
    public void startRateSpider() {
        Spider.create(new CurrRateBocPageProcessor())
                .addPipeline(new CurrRateBocPipeline(currRateService, currencyService))
                .addUrl("https://www.boc.cn/sourcedb/whpj/")
                .thread(1)
                .setExitWhenComplete(true)
                .start(); //非阻塞
    }

    @Override
    public void saveCustomsRate() {
        // 1、查询需要更新的币种
        List<CurrencyVo> currencyVos = currencyService.listAll(CommonEnum.CommonStatusEnum.OK.getCode());
        if (CollectionUtils.isEmpty(currencyVos)) {
            throw new BadRequestException("没有币种，海关汇率同步失败！");
        }
        // 2、确定日期（每月第三周星期三）
        String wednesdayToDate = DateTimeUtils.getPreMonthThrWen();
        // 3、获取该日期的历史汇率
        List<String> currencyCodes = currencyVos.stream().map(CurrencyVo::getCode)
                .filter(Objects::nonNull).collect(Collectors.toList());
        List<CurrRateHisVo> currRateHisVos = currRateHisService.queryCurrRateByCodeAndDate(currencyCodes, wednesdayToDate);
        if (CollectionUtils.isEmpty(currRateHisVos)) {
            log.error("未找到历史汇率数据:{}", wednesdayToDate);
            return;
        }
        // 按创建时间，获取币种的最新的一个汇率（当天可能存在同一币种的多条历史汇率）
        Collection<CurrRateHisVo> currRateHisVoColl = currRateHisVos.stream()
                .collect(Collectors.toMap(CurrRateHisVo::getCurrency, Function.identity(), (v1, v2) -> {
                    Date hisTime1 = v1.getHisTime();
                    Date hisTime2 = v2.getHisTime();
                    if (hisTime1.compareTo(hisTime2) < 0) {
                        return v2;
                    } else {
                        return v1;
                    }
                })).values();
        // 4、处理新增或更新海关汇率
        List<CurrRateVo> currRateVos = currRateService.addCustomsRate(currencyVos, new ArrayList<>(currRateHisVoColl));
        // 5、保存到历史汇率表
        currRateHisService.addTbCurrRateHis(currRateVos);
    }



}
